#include <sys_config.h>

#ifdef AUTO_UPDATE_TPINFO_SUPPORT
#include <types.h>
#include <api/libsi/sie_monitor.h>
#include <api/libpub/lib_frontend.h>
#include <api/libsi/si_module.h>
#include <api/libsubt/lib_subt.h>
#include <api/libsi/si_tdt.h>
#include <api/libtsi/psi_db.h>
#include <hld/decv/decv.h>
#include <api/libpub/lib_device_manage.h>
#include "control.h"
#include "menus_root.h"
#include "win_com_popup.h"
#include "si_auto_update_tp.h"
#include "win_password.h"
#include "key.h"

//#define AUTO_UPDATE_DEBUG
#ifdef AUTO_UPDATE_DEBUG
#define AUTP_PRINTF libc_printf
#else
#define AUTP_PRINTF(...) do{}while(0)
#endif

enum {
	GET_CRC_VALUE_VARIABLE			= 0x02000000UL,
};

struct new_prog {
    UINT32 prog_id;
    UINT8 av_flag;
}; 

static struct new_prog new_progs[PROGRAM_NUM];
static UINT32 new_prog_num = 0;

#ifdef _LCN_ENABLE_
static UINT16 lcn_value = 0xFFFF;
#endif

#ifdef AUDIO_DESCRIPTION_SUPPORT
static BOOL ad_is_open = FALSE;
#endif
#define COUNT_TIMES 3
static T_NODE cur_sim_tnode;
static BOOL is_open_notice = FALSE;
static BOOL play_back_flag = FALSE;
static BOOL stream_change = FALSE;
static UINT32 oldCRC = 0xFFFFFFFF;
static struct ts_route_info ts_route;

static void play_default_program();
static void del_progs_under_tp();

void reset_variable()
{
    MEMSET(new_progs, 0, PROGRAM_NUM * sizeof(struct new_prog));

    #ifdef _LCN_ENABLE_
    lcn_value = 0xFFFF;
    #endif
    
    new_prog_num = 0;
    stream_change = FALSE;
    play_back_flag = FALSE;
}

void set_oldCRC_value(void)
{
    oldCRC = cur_sim_tnode.crc_h8 << 24 | cur_sim_tnode.crc_t24;
}

BOOL get_stream_change_flag()
{
    return stream_change;
}

void save_new_progs(UINT32 prog_id, UINT8 av_flag)
{
    if(prog_id != 0x1FFF)
    {
        new_progs[new_prog_num].prog_id = prog_id;
        new_progs[new_prog_num].av_flag = av_flag;
        ++new_prog_num;
    }
}

static void srch_handler(UINT8 aue_type, UINT32 aue_value)
{
    UINT32 msg_type = 0;
    UINT32 msg_code = 0;
    
    if(aue_type == ASM_TYPE_PROGRESS && aue_value == AS_PROGRESS_SCANOVER)
    {
        msg_type = CTRL_MSG_SUBTYPE_CMD_UPDATE_TPINFO;
        msg_code = CTRL_MSG_SUBTYPE_CMD_PLAY_CHANNEL;
        ap_send_msg(msg_type, msg_code, TRUE);
    }
    else
        return ;
}

static INT32 tp_search_set_param(T_NODE* t_node, struct as_service_param* as_param)
{
    if(t_node == NULL || as_param == NULL)
    {
        return ERR_FAILUE;
    }
    else
    {
    	struct as_service_param* param = as_param;
    	struct vdec_device *vdec = NULL;
    	struct vdec_io_get_frm_para vfrm_param;
        UINT32  search_mode = 0;
	    UINT32 prog_type = 0;
    	UINT32 addr = 0;
        UINT32 len = 0;
    	T_NODE cur_t_node = *t_node;
        UINT16 cur_ft_type = t_node->ft_type;
        INT32 ret = 0;

    	recreate_tp_view(VIEW_SINGLE_SAT, 1);

        switch(cur_t_node.ft_type)
        {
            case FRONTEND_TYPE_T:
                {
                	ret = lookup_node(TYPE_TP_NODE, &cur_t_node, cur_t_node.sat_id);
                	if (ret != SUCCESS)
                	{
                		add_node(TYPE_TP_NODE, cur_t_node.sat_id, &cur_t_node);
                		update_data();
                	}
                    
                    param->as_frontend_type = FRONTEND_TYPE_T;
                    param->as_method = AS_METHOD_FREQ_BW;
                    param->as_sat_cnt = 1;
    	            param->sat_ids[0] = cur_t_node.sat_id;// MAX_SAT_NUM-1;//1;
                }
                break;
            case FRONTEND_TYPE_S:
                {
                #ifdef NEW_DEMO_FRAME
                	param->as_frontend_type = FRONTEND_TYPE_S;
                	param->as_sat_cnt = 1;
                	param->sat_ids[0] = cur_t_node.sat_id;
                #else	
                	param->as_sat_id = cur_t_node.sat_id;
                #endif	
                    param->as_method = AS_METHOD_TP;
                }
                break;
            case FRONTEND_TYPE_C:
                {
                    param->as_method = AS_METHOD_TP;
                	param->as_sat_cnt = 1;
                	param->sat_ids[0] = cur_t_node.sat_id;
                	param->as_frontend_type = FRONTEND_TYPE_C;
                    param->ft_count=0;
                }
                break;
            default:
                break;
        }

        param->as_p_add_cfg = PROG_ADD_REPLACE_OLD;
        prog_type = P_SEARCH_TV | P_SEARCH_RADIO;
        search_mode = P_SEARCH_FTA | P_SEARCH_SCRAMBLED;
        param->as_prog_attr = prog_type | search_mode;
        param->as_from = cur_t_node.tp_id;
        param->as_to = 0;
        param->as_handler = srch_handler;

    	update_data();
            
        if(cur_t_node.ft_type != FRONTEND_TYPE_C)
        {	
        	addr = __MM_AUTOSCAN_DB_BUFFER_ADDR;
        	addr &= 0x8fffffff;
        	len = __MM_AUTOSCAN_DB_BUFFER_LEN;
        }
        else
        {
            vdec = (struct vdec_device *)dev_get_by_id(HLD_DEV_TYPE_DECV, 0);
        	vfrm_param.ufrm_mode = VDEC_UN_DISPLAY;
        	vdec_io_control(vdec, VDEC_IO_GET_FRM, (UINT32)&vfrm_param);
        	addr = vfrm_param.tFrmInfo.uY_Addr;
        	len = (vfrm_param.tFrmInfo.uHeight * vfrm_param.tFrmInfo.uWidth * 3) / 2;
        }

    	db_search_init((UINT8 *)addr, len);

        return SUCCESS;
    }
}

static void stop_all_pvr(void)
{  
    UINT8 cur_rec_num = pvr_info.rec_num;

    if(cur_rec_num > 0)
    {
		api_stop_play_record(FALSE);

#ifdef MULTI_DESCRAMBLE
        int dmx_index = 0;
        for(dmx_index = 0; dmx_index < 3;dmx_index++)
        {
            api_mcas_stop_transponder_multi_des(dmx_index);
        }
        struct ts_route_info ts_route_local;
	    INT32 ts_route_id;
        if(ts_route_get_by_type(TS_ROUTE_MAIN_PLAY, &ts_route_id, &ts_route_local) != RET_FAILURE)
        {
            api_mcas_stop_service_multi_des(ts_route_local.prog_id,0xffff);
        }        
#endif

        P_NODE pnode;
        BOOL ret = FALSE;
        MEMSET(&pnode, 0, sizeof(P_NODE));

        if(pvr_info.rec[0].record_chan_flag == 1)
        {   
            api_stop_record(pvr_info.rec[0].record_handle, 1);
        }

        if(pvr_info.rec[1].record_chan_flag == 1)
        {
            api_stop_record(pvr_info.rec[1].record_handle, 1);
        }
    }
}

BOOL check_pvr_state()
{
    BOOL ret = FALSE;
    UINT8 i = 0;
    UINT8 num = pvr_info.rec_num;
    UINT32 rec_id = 0;
    P_NODE pnode;
    MEMSET(&pnode, 0, sizeof(P_NODE));
    
    if(num > 0)
    {
        for(i = 0; i < num; ++i)
        {
            if(pvr_info.rec[i].record_chan_flag == 1)
            {
                rec_id = pvr_info.rec[i].record_chan_id;
                get_prog_by_id(rec_id, &pnode);

                if(pnode.tp_id != cur_sim_tnode.tp_id)
                    ret = TRUE;
            }
        }
    }

    return ret;
}

BOOL check_timer(UINT32 prog_id)
{
    P_NODE pnode;
    MEMSET(&pnode, 0, sizeof(P_NODE));

    if(get_prog_by_id(prog_id, &pnode) == DB_SUCCES)
    {
        if(pnode.tp_id == cur_sim_tnode.tp_id)
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    else
        return FALSE;
}

static BOOL clear_all_timer()
{
    int i = 0;
    UINT16 total = 0;
    TIMER_SET_CONTENT* timer;
	SYSTEM_DATA *sys_data = sys_data_get();
    if (sys_data == NULL)
        return FALSE;
    else
    {
        total = sys_data->timer_set.common_timer_num + sys_data->timer_set.record_timer_num;
        for(i = 0; i < total; ++i)
        {
            timer = &(sys_data->timer_set.TimerContent[i]);
            if(check_timer(timer->wakeup_channel))
            {
                if(timer->wakeup_state == TIMER_STATE_READY)
                {                   
                    timer->timer_mode = TIMER_MODE_OFF;
                }
            }
        }
        
        ap_send_msg(CTRL_MSG_SUBTYPE_CMD_SYSDATA_SAVE,0,FALSE);
        
        return TRUE;
    }
}

void stop_time_shift(void)
{
	if(pvr_info.tms_enable)
	{
	    api_stop_tms_record();
	}
}

static INT32 prepare_tp_scan(T_NODE* t_node, struct as_service_param* as_param)
{
    if(t_node == NULL || as_param == NULL)
    {
        return ERR_FAILUE;
    }
    else
    {  
        stop_all_pvr();
        //stop_time_shift();
        clear_all_timer();
        pid_callback_register(save_new_progs);
        
        if(tp_search_set_param(t_node, as_param) == SUCCESS)
        {
            return SUCCESS;
        }
        else
        {
            return ERR_FAILUE;
        }
    }
}

static INT32 start_tp_scan(T_NODE* t_node)
{
    if(t_node == NULL)
        return ERR_FAILUE;
    else
    {
        struct as_service_param as_param;
        MEMSET(&as_param, 0, sizeof(struct as_service_param));
        
        INT32 ret = prepare_tp_scan(t_node, &as_param);
        if(ret != SUCCESS)
            return ERR_FAILUE;
        else
        {
            ap_clear_all_message();
            epg_off();
            epg_reset();
            as_service_start(&as_param);
            return SUCCESS;
        }
    }
}

void win_popup_notice_menu()
{
    INT32 ret = 0;
    
    if(menu_stack_get_top() != NULL)
    {
        menu_stack_pop_all();
    }
    ap_clear_all_menus();

	win_compopup_init(WIN_POPUP_TYPE_SMSG);
    #ifdef SD_UI
    win_compopup_set_frame(110, 200, 700, 100);
    #else

    #ifdef FONT_1BIT_SUPPORT
    win_compopup_set_frame(200,250,630,150);
    #else
    win_compopup_set_frame(200, 250, 600, 150);
    #endif
    
    #endif
	win_compopup_set_msg_ext("Auto update TP information, please wait!",NULL,0);
	win_compopup_open();
    is_open_notice = TRUE;
    
	api_set_system_state(SYS_STATE_SEARCH_PROG);

	ap_filter_specific_msg();
}

BOOL win_popup_enquire_menu()
{
    UINT8 	back_saved;
    PRESULT	ret;
	win_compopup_init(WIN_POPUP_TYPE_OKNO);
	win_compopup_set_msg("Program under current TP has changed!\nSelect [YES] will STOP all Record and update program.\nSelect [NO] continue record without update!",NULL,0);
	
	win_compopup_set_default_choice(WIN_POP_CHOICE_YES);
	ret = win_compopup_open_ext(&back_saved);
	if(ret==WIN_POP_CHOICE_YES)
 	{
        return TRUE;
 	}
    else
        return FALSE;
}

BOOL check_each_program(UINT32 monitor_id)
{
    DB_VIEW *cur_view = NULL;
    BOOL flag = FALSE;
    UINT16 old_view_type = 0xFFFF;
    UINT32 old_param = 0xFFFFFFFF;
    INT16 prog_num_cur = 0; 
    INT16 prog_num_db = 0; 

    prog_num_cur = sim_get_prog_number(monitor_id);
    cur_view = (DB_VIEW *)get_cur_view();
    old_view_type = cur_view->cur_filter_mode;
    old_param = cur_view->view_param;

    if((cur_view->cur_filter_mode != (VIEW_SINGLE_TP | PROG_TVRADIO_MODE)) || 
    (cur_view->cur_filter_mode == (VIEW_SINGLE_TP | PROG_TVRADIO_MODE) && (cur_view->view_param != cur_sim_tnode.tp_id)))
    {
	    recreate_prog_view(VIEW_SINGLE_TP | PROG_TVRADIO_MODE, cur_sim_tnode.tp_id);
	    flag = TRUE;
    }
    prog_num_db = get_prog_num(VIEW_SINGLE_TP | PROG_TVRADIO_MODE, cur_sim_tnode.tp_id);

    if(flag)
    {
        recreate_prog_view(old_view_type, old_param);
        flag = FALSE;
    }

    if(prog_num_cur > prog_num_db)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

BOOL check_front_end_type(UINT8 nim_id, T_NODE* tnode)
{
    if(tnode == NULL)
        return FALSE;

    UINT32 ft_type = 0;
    struct nim_device* nim = NULL;
    struct nim_config config;
    MEMSET(&config, 0, sizeof(struct nim_config));

    nim = dev_get_by_id(HLD_DEV_TYPE_NIM, nim_id);
    ft_type = dev_get_device_sub_type(nim, HLD_DEV_TYPE_NIM);
    dev_get_nim_config(nim, ft_type, &config);

    if(ft_type == FRONTEND_TYPE_S)
    {
        if(config.xpond.s_info.tp_id == tnode->tp_id && 
            config.xpond.s_info.frq == tnode->frq && 
            config.xpond.s_info.sym == tnode->sym &&
            config.xpond.s_info.pol == tnode->pol &&
            config.xpond.s_info.type == tnode->ft_type)
            return TRUE;
        else
            return FALSE;
    }
    else if(ft_type == FRONTEND_TYPE_T)
    {
        if(config.xpond.t_info.tp_id == tnode->tp_id && 
            config.xpond.t_info.frq == tnode->frq &&
            config.xpond.t_info.type == tnode->ft_type &&
            config.xpond.t_info.sym == tnode->sym &&
            config.xpond.t_info.band_width == (tnode->bandwidth * 1000))
            return TRUE;
        else
            return FALSE;
    }
    else if(ft_type == FRONTEND_TYPE_C)
    {
        if(config.xpond.c_info.tp_id == tnode->tp_id &&
            config.xpond.c_info.frq == tnode->frq &&
            config.xpond.c_info.sym == tnode->sym)
            return TRUE;
        else
            return FALSE;
    }
    else
    {
        return FALSE;
    }
}

BOOL check_CRC_value(UINT8* data, INT32 length, T_NODE* tnode, UINT8 dmx_id_p, UINT8 dmx_id_r, UINT8 nim_id)
{
    if(data == NULL)
        return FALSE;

    static UINT8 i = 0;
    UINT32 crcdb = 0;
    OSAL_ID flag_id = OSAL_INVALID_ID;
    UINT32 flag = 0;
    UINT32 curCRC = 0;
    UINT32* crcAddr = data + (length - PSI_SECTION_CRC_LENGTH);
    curCRC = (UINT32)(*crcAddr); 
    crcdb = tnode->crc_h8 << 24 | tnode->crc_t24;
    AUTP_PRINTF("[%s]: curCRC=0x%x, crcdb=0x%x, oldCRC=0x%x\n", __FUNCTION__, curCRC, crcdb, oldCRC);

    if(!check_front_end_type(nim_id, tnode))
    {
        return FALSE;
    }

    osal_flag_wait(&flag, flag_id, GET_CRC_VALUE_VARIABLE, OSAL_TWF_ORW, OSAL_WAIT_FOREVER_TIME);

    if(oldCRC == curCRC)
    {
        if(i == COUNT_TIMES)
        {
            if(curCRC != crcdb && dmx_id_p == dmx_id_r)
            {
                i = 0;
                return TRUE;
            }
        }

        ++i;
        return FALSE;
    }
    else
    {
        i = 0;
    }
    
    osal_flag_clear(flag_id, GET_CRC_VALUE_VARIABLE);
	osal_flag_set(flag_id, GET_CRC_VALUE_VARIABLE);

    if(curCRC != crcdb)   
    {
        if(dmx_id_p == dmx_id_r)
        {
            return TRUE;
        }
        else
            return FALSE;
    }
    else                  
    {
        return FALSE;
    }

}

BOOL launch_TP_scan(struct ts_route_info* ts_route)
{
    UINT32 msg_type = 0;
    UINT32 msg_code = 0;
    BOOL ret = FALSE;
    
#ifdef MP_PREVIEW_SWITCH_SMOOTHLY
    POBJECT_HEAD topmenu = menu_stack_get_top();
#endif

    #ifdef MP_PREVIEW_SWITCH_SMOOTHLY
    if(topmenu == (POBJECT_HEAD)&g_win_epg)
    {
        set_oldCRC_value();
        return FALSE;
    }
    #endif
    
    #ifdef AUDIO_DESCRIPTION_SUPPORT
    ad_is_open = sys_data_get_ad_service();
    if(ad_is_open)
        sys_data_set_ad_service(FALSE);
    #endif
    
    if(!play_back_flag)
    {
    	api_osd_mode_change(OSD_NO_SHOW);
    	api_sim_stop(ts_route);
        set_oldCRC_value();

        msg_type = CTRL_MSG_SUBTYPE_CMD_UPDATE_TPINFO;
        msg_code = CTRL_MSG_SUBTYPE_CMD_START_TP_SCAN;
        ap_send_msg(msg_type, msg_code, TRUE);

        if(pvr_info.pvr_state == PVR_STATE_TMS_PLAY || pvr_info.pvr_state == PVR_STATE_REC_PLAY)
        {
            play_back_flag = TRUE;
        }
        
        return TRUE;
    }
    else
    {
        if(play_back_flag)
        {
            play_back_flag = FALSE;
        }
        
        return FALSE;
    }
}

INT32 sim_pat_callback(UINT8* section, INT32 length, UINT32 param)
{
    P_NODE p_node;
    T_NODE t_node;
    MEMSET(&p_node, 0, sizeof(P_NODE));
    MEMSET(&t_node, 0, sizeof(T_NODE));

    static UINT8 j = 0;
    MEMSET(&ts_route, 0, sizeof(struct ts_route_info));
    INT32 ts_route_id = 0;
    UINT16 pmt_pid = 0;
    INT32 is_print = 0;
    RET_CODE getRouteRet = 0;
    POBJECT_HEAD topmenu = menu_stack_get_top();

#ifdef MP_PREVIEW_SWITCH_SMOOTHLY
    if(topmenu != (POBJECT_HEAD)&g_win_epg)
    {
#endif
    if(j < 4)
    {
        ++j;
        return RET_FAILURE;
    }
#ifdef MP_PREVIEW_SWITCH_SMOOTHLY
    }
#endif
    
    struct sim_cb_param* sim_param = (struct sim_cb_param*)param;
    if(sim_param->table == MONITE_TB_PAT)
    {
        j = 0;
        if(pvr_info.pvr_state == PVR_STATE_TMS_PLAY || pvr_info.pvr_state == PVR_STATE_REC_PLAY)
        {
            getRouteRet = ts_route_get_by_type(TS_ROUTE_BACKGROUND, &ts_route_id, &ts_route);
        }
        else
        {
            getRouteRet = ts_route_get_by_type(TS_ROUTE_MAIN_PLAY, &ts_route_id, &ts_route);
        }
        
        if(getRouteRet != RET_FAILURE)
        {
            if((get_prog_by_id(ts_route.prog_id, &p_node) == SUCCESS) && (get_tp_by_id(p_node.tp_id, &t_node) == SUCCESS))
            {
                MEMCPY(&cur_sim_tnode, &t_node, sizeof(T_NODE));
                //topmenu = menu_stack_get_top();
                sys_state_t sys_state = api_get_system_state();
                BOOL is_msg_popup = win_msg_popup_opend();
                UINT8 disk_operate_opened = is_disk_operate_opened();

                if((topmenu == NULL && sys_state != SYS_STATE_TEXT && !disk_operate_opened && !is_msg_popup) || 
                    (topmenu != NULL && ((topmenu == (POBJECT_HEAD)&g_win_light_chanlist) || (topmenu == (POBJECT_HEAD)&g_win_progname)
                    #ifdef MP_PREVIEW_SWITCH_SMOOTHLY
                    || (topmenu == (POBJECT_HEAD)&g_win_epg)
                    #endif
                    )))
                {
                   if(check_CRC_value(section, length, &t_node, (UINT8)sim_param->dmx_idx, ts_route.dmx_id, ts_route.nim_id))
                   {                             
                        if(get_pwd_is_open())
                        {
                            ap_send_key(V_KEY_EXIT, FALSE);
                            ap_send_key(V_KEY_EXIT, FALSE);
                            ap_send_key(V_KEY_EXIT, FALSE);
                        }
                    
                        UINT32 matchCnt = sim_get_prog_pmt_pid(sim_param->sim_id, p_node.prog_number, &pmt_pid);
                        if(matchCnt == 0)
                        {
                            stream_change = TRUE;
                            if(launch_TP_scan(&ts_route))
                            {
                                AUTP_PRINTF("[%s]: matchCnt = %d, launch TP scan\n", __FUNCTION__, matchCnt);
                                return SUCCESS;
                            }
                            else
                                return ERR_FAILUE;
                        }
                        else if(matchCnt == 1)
                        {
                            UINT16 cur_ts_id = (section[3]<<8)|section[4];

                            if(cur_ts_id == t_node.t_s_id)
                        {
                            if(p_node.pmt_pid != pmt_pid)
                            {
                                if(ts_route.dmx_sim_info[0].sim_type != MONITE_TB_PMT)
                                    return ERR_FAILUE;

                                if(ts_route.dmx_sim_info[0].sim_id != INVALID_SIM_ID)
                                {
                                    if(sim_stop_monitor(ts_route.dmx_sim_info[0].sim_id) != SUCCESS)
                                        AUTP_PRINTF("\tCan not stop monitor!\n");
                                    ts_route.dmx_sim_info[0].sim_id = INVALID_SIM_ID;
                                }

                                p_node.pmt_pid = pmt_pid;
                                modify_prog(p_node.prog_id, &p_node);
                                update_data();

                                UINT32 new_sim_id = INVALID_SIM_ID;
                                new_sim_id = sim_start_monitor(((sim_param->dmx_idx == 0) ? g_dmx_dev : ((sim_param->dmx_idx == 1) ? g_dmx_dev2 : g_dmx_dev3)), \
						            MONITE_TB_PMT, p_node.pmt_pid, p_node.prog_number);

                                if(new_sim_id == INVALID_SIM_ID)
                                {
                                    AUTP_PRINTF("\nStart new monitor failue!\n");
                                    return ERR_FAILUE;
                                }
                                sim_register_ncb(new_sim_id, api_sim_callback);

                                ts_route.dmx_sim_info[0].sim_id = new_sim_id;
                                ts_route.dmx_sim_info[0].sim_pid = pmt_pid;
                                ts_route_update(ts_route_id, &ts_route);
                            }
                            else
                            {
                                stream_change = TRUE;
                                if(check_each_program(sim_param->sim_id))
                                {
                                    if(launch_TP_scan(&ts_route))
                                        return SUCCESS;
                                    else
                                        return ERR_FAILUE;
                                }
                            }
                            }
                            else
                            {
                                stream_change = TRUE;
                                if(launch_TP_scan(&ts_route))
                                {
                                    AUTP_PRINTF("[%s]: cur_ts_id:%d, db_ts_id:%d launch TP scan\n", __FUNCTION__, cur_ts_id, t_node.t_s_id);
                                    return SUCCESS;
                                }
                                else
                                    return ERR_FAILUE;
                            }
                        }
                        else
                        {
                            return SUCCESS;
                        }
                    }
                }
            }
        }   

    }

   return ERR_FAILUE;

}

BOOL is_new_prog(UINT32 prog_id)
{
    INT32 i = 0;
    INT32 j = new_prog_num - 1;
    INT32 mid = 0;

    if(new_progs[i].prog_id== prog_id)
        return TRUE;

    if(new_progs[j].prog_id == prog_id)
        return TRUE;

    while(i <= j)
    {
        mid = i + (j - i)/2;

        if(new_progs[mid].prog_id == prog_id)
            return TRUE;
        else
        {
            if(prog_id < new_progs[mid].prog_id)
                j = mid -1;

            if(prog_id > new_progs[mid].prog_id)
                i = mid + 1;
        }
    }

    if(i > j)
        return FALSE;
}

BOOL is_new_prog_saved(void)
{
    if(new_prog_num > 0)
    {
        P_NODE pnode;
        MEMSET(&pnode, 0, sizeof(P_NODE));

        if(new_prog_num == 1)
        {
            if(get_prog_by_id(new_progs[0].prog_id, &pnode) == DB_SUCCES)
                return TRUE;
            else
                return FALSE;
        }
        else
        {
            if((get_prog_by_id(new_progs[0].prog_id, &pnode) == DB_SUCCES) &&
                get_prog_by_id(new_progs[new_prog_num - 1].prog_id, &pnode) == DB_SUCCES)
                return TRUE;
            else
                return FALSE;
        }
    }
    else
        return FALSE;
}

#ifdef _LCN_ENABLE_
void change_node_LCN(UINT8 flag, UINT8 prog_num)
{
    INT32 i = 0;
    P_NODE pnode;
    MEMSET(&pnode, 0, sizeof(P_NODE));
    
    for(i = 0; i < prog_num; ++i)
    {
        if(get_prog_at(i, &pnode) == DB_SUCCES)
        {
            if(pnode.LCN_true == FALSE && (flag ? (pnode.LCN > lcn_value) : 1))
            {
                pnode.LCN = lcn_value;
                modify_prog(pnode.prog_id, &pnode);
                ++lcn_value;
            }
        }
    }
    
    sort_prog_node(PROG_LCN_SORT);
    update_data();
}
#endif

static void del_progs_from_view(UINT16 prognum)
{
    int n = prognum - 1;
    BOOL flag = FALSE;
    
    P_NODE p_node;
    MEMSET(&p_node, 0, sizeof(P_NODE));

    while(n >= 0)
    {
        if(get_prog_at(n, &p_node) == DB_SUCCES)
        {
            if(p_node.tp_id == cur_sim_tnode.tp_id && !is_new_prog(p_node.prog_id))
            {
                del_prog_at((UINT16)n);
                flag = TRUE;

                #ifdef _LCN_ENABLE_
                if(p_node.LCN_true == FALSE)
                {
                    if(p_node.LCN < lcn_value)
                        lcn_value = p_node.LCN;
                }
                #endif
            }
        }
        --n;
    }

    if(flag)
        update_data();
}

#ifdef _LCN_ENABLE_
void modify_LCN()
{
    if(sys_data_get_LCN() && lcn_value != 0xFFFF)
    {
        UINT16 number = 0;

        recreate_prog_view(VIEW_ALL | TV_CHAN, 0);
        number = get_prog_num(VIEW_ALL | TV_CHAN, 0);
        if(number > 0)
        change_node_LCN(TV_CHAN, number);

        
        recreate_prog_view(VIEW_ALL | RADIO_CHAN, 0);
        number = get_prog_num(VIEW_ALL | RADIO_CHAN, 0);
        if(number > 0)
        {
            change_node_LCN(RADIO_CHAN, number);
        }
    }
}
#endif

BOOL swap(UINT8 i, UINT8 j)
{
    struct new_prog temp;
    temp = new_progs[i];
    new_progs[i] = new_progs[j];
    new_progs[j] = temp;

    return TRUE;
}

void sort_new_prog()
{
    UINT8 i = 0;
    UINT8 j = 0;
    BOOL flag = FALSE;

    for(i = 0; i < new_prog_num - 1; ++i)
    {
        flag = TRUE;

        for(j = 0; j < new_prog_num - i -1; ++j)
        {
            if(new_progs[j].prog_id > new_progs[j+1].prog_id)
            {
                if(swap(j,j+1))
                    flag = FALSE;
            }
        }

        if(flag)
            break;
    }
}

static void del_progs_under_tp()
{
    UINT16 progNum = 0;

    if(!is_new_prog_saved())
        return ;
    if(new_prog_num > 1)
    {
        if(new_prog_num == 2 && new_progs[0].prog_id > new_progs[1].prog_id)
        {
            swap(0,1);
        }
        else
        {
            sort_new_prog();
        }
    }

    recreate_prog_view(VIEW_ALL | TV_CHAN, 0);
    progNum = get_prog_num(VIEW_ALL | PROG_TVRADIO_MODE, 0);
    if(progNum > 0)
    {
        del_progs_from_view(progNum);
    }

    recreate_prog_view(VIEW_ALL | RADIO_CHAN, 0);
    progNum = get_prog_num(VIEW_ALL | PROG_TVRADIO_MODE, 0);
    if(progNum > 0)
    {
        del_progs_from_view(progNum);
    }

#ifdef _LCN_ENABLE_

    modify_LCN();

#endif

}

static UINT32 get_last_pid_in_cur_group(UINT16 index)
{
    P_NODE pnode;
    MEMSET(&pnode, 0, sizeof(P_NODE));

    if(get_prog_at(index, &pnode) == DB_SUCCES)
    {
        return pnode.prog_id;
    }
    else
        return 0xFFFFFFFF;
}

static UINT32 get_a_new_prog(UINT8 av_flag)
{
    UINT16 prog_num = 0;
    UINT16 channel = 0;
    UINT32 sele_pid = 0xFFFFFFFF;
    
    if(av_flag == TV_CHAN)
    {
        prog_num = get_prog_num(VIEW_ALL | PROG_TV_MODE, 0);
        if(prog_num - 1 >= 0)
        {
            sele_pid =  get_last_pid_in_cur_group(prog_num - 1);
        }
        else
        {
            ap_send_key(V_KEY_MENU,FALSE);
        }
    }
    else if(av_flag == RADIO_CHAN)
    {
        prog_num = get_prog_num(VIEW_ALL | PROG_RADIO_MODE, 0);
        if(prog_num - 1 >= 0)
        {
            sele_pid =  get_last_pid_in_cur_group(prog_num - 1);
        }
        else
        {
            ap_send_key(V_KEY_MENU,FALSE);
        }
    }
    else
        sele_pid = 0xFFFFFFFF;

    return sele_pid;
}

static void play_default_program()
{
    UINT32 prog_id = 0;
    UINT32 grp_idx = 0;
    UINT16 channel = 0;
    UINT8 av_flag = 0;
    UINT8 prog_num = 0;
    INT32 ret = 0;

    ret = recreate_tp_view(VIEW_ALL | PROG_TVRADIO_MODE, 0);
    reset_group();
    grp_idx = sys_data_get_cur_group_index();
    sys_data_check_channel_groups();
    sys_data_set_cur_group_index(grp_idx);
    
    av_flag = sys_data_get_cur_chan_mode();
    prog_num = sys_data_get_sate_group_num(av_flag);
	if(prog_num == 0)
	{
		av_flag = (av_flag == TV_CHAN)? RADIO_CHAN : TV_CHAN;
		sys_data_set_cur_chan_mode(av_flag);
	}
    sys_data_change_group(grp_idx);
    sys_data_save(1);    

    prog_id = get_a_new_prog(av_flag);

#if defined( SUPPORT_CAS9) || defined(SUPPORT_VMX) || defined(SUPPORT_VMX_STD) //bug4759 need call <api_mcas_start_transponder>
	struct nim_device *nim = (struct nim_device *)dev_get_by_id(HLD_DEV_TYPE_NIM, cur_tuner_idx);
	UINT32 nim_sub_type = dev_get_device_sub_type(nim, HLD_DEV_TYPE_NIM);
	struct nim_config config;
	dev_get_nim_config(nim, nim_sub_type, &config);
	if(nim_sub_type == FRONTEND_TYPE_C)
		config.xpond.c_info.frq = 0;
    frontend_set_nim(nim, NULL, &config.xpond, 1);
    key_set_signal_check_flag(SIGNAL_CHECK_PAUSE);
#endif
    
    if(prog_id != 0xFFFFFFFF)
    {
        api_play_channel(prog_id, TRUE, FALSE, TRUE);
    }
    else
    {
        channel = sys_data_get_cur_group_cur_mode_channel();
	    api_play_channel(channel, TRUE, FALSE, FALSE);
    }
    reset_variable();
}

void do_update_process()
{
    //subt_show_onoff(FALSE);

    #ifdef CI_SUPPORT
    win_ci_dlg_close();
    set_ci_dlg_openning(TRUE);
    #endif
    
    start_tp_scan(&cur_sim_tnode);
    win_popup_notice_menu();
}

void auto_update_tpinfo_msg_proc(UINT32 msg_type,UINT32 msg_code)
{
    if(msg_type == CTRL_MSG_SUBTYPE_CMD_UPDATE_TPINFO)
    {
        if(msg_code == CTRL_MSG_SUBTYPE_CMD_START_TP_SCAN)
        {
            api_stop_play_prog(&ts_route);
            if(check_pvr_state())
            {
                if(win_popup_enquire_menu())
                {
                    do_update_process();
                }
                else
                {
                    #ifdef AUDIO_DESCRIPTION_SUPPORT
                    if(ad_is_open)
                        sys_data_set_ad_service(TRUE);
                    #endif
                }
            }
            else
            {
                do_update_process();
            }

        }
        else if(msg_code == CTRL_MSG_SUBTYPE_CMD_PLAY_CHANNEL)
        {
            as_service_stop();
            db_search_exit();
            del_progs_under_tp();
            pid_callback_unregister();

            if(get_tdt_parsing())
            {
                set_tdt_parsing(FALSE);
                start_tdt();
            }
            
            api_set_system_state(SYS_STATE_NORMAL);
            if(is_open_notice)
            {
                win_compopup_close();
                OSD_ClearScreen();
                is_open_notice = FALSE;
            }
            ShowMuteOnOff();
            ShowRecHintOSDOnOff(GetRecHintState());
            //subt_show_onoff(TRUE);

            #ifdef AUDIO_DESCRIPTION_SUPPORT
            if(ad_is_open)
                sys_data_set_ad_service(TRUE);
            #endif

            #ifdef CI_SUPPORT
            set_ci_dlg_openning(FALSE);
            #endif
            
            play_default_program();
        }
    }
}

#endif

